home *** CD-ROM | disk | FTP | other *** search
- unit uSyncPhonebook;
-
- {
- *******************************************************************************
- * Descriptions: Synchronize's Phonebook Interface
- * $Source: /cvsroot/fma/fma/uSyncPhonebook.pas,v $
- * $Locker: $
- *
- * Todo:
- *
- * Change Log:
- * $Log: uSyncPhonebook.pas,v $
- * Revision 1.40.2.3 2005/01/25 16:03:20 z_stoichev
- * Merged with 2.1 Beta 1 bugfixes
- *
- * Revision 1.40.2.2 2004/09/10 07:31:42 z_stoichev
- * Fixed a typo in Outlook Details
- * Added Outlook Details default number
- *
- * Revision 1.40.2.1 2004/09/08 19:24:25 lordlarry
- * New Line Char in Contact Name is read properly from the Contacts.SYNC.dat file too
- *
- * Revision 1.40 2004/08/27 20:42:00 lordlarry
- * Merge from newxml
- *
- * Revision 1.39.4.1 2004/08/25 15:40:20 merijnb
- * implemented xml parser
- *
- * Revision 1.39 2004/07/14 09:43:07 z_stoichev
- * - Fixed Add to Group disabled for new/del contacts.
- *
- * Revision 1.38 2004/07/06 13:51:04 z_stoichev
- * - Fixed Keep FMA settings on full PB refresh.
- * - Fixed Contact doubled if changed in phone.
- *
- * Revision 1.37 2004/07/01 15:02:17 z_stoichev
- * Fixed Phonebook View First-Last name order.
- *
- * Revision 1.36 2004/07/01 14:39:21 z_stoichev
- * Remember columns sort and order.
- * vCard notes support.
- *
- * Revision 1.35 2004/06/30 16:13:14 z_stoichev
- * Fixed Add to Group canceled but shows Adding.
- *
- * Revision 1.34 2004/06/29 10:48:38 z_stoichev
- * Added contact call notes support
- *
- * Revision 1.33 2004/06/24 14:56:03 z_stoichev
- * - Fixed Upload Contacts phone type to SIM issues.
- * - Fixed Max field length for ME and SM Phonebooks.
- * - Fixed Contact name lookup routines use ME phonebook.
- * - Changed Connect after unknown number call is entered.
- * - Changed Explorer Popup menu reorganized.
- * - Added Chat to Contact command to various popup menus.
- * - Added Add to Phonebook to various popup menus.
- * - Added hit Enter in SIM editor to edit contact.
- * - Added Remove favorite item confirmation message.
- * - Added Download entire SIM phonebook.
- * - Added New SIM editor columns (phone type, status).
- * - Broken Phonebook editors Sorting is not remembered.
- *
- * Revision 1.32 2004/06/24 09:00:00 z_stoichev
- * Find contact by number
- *
- * Revision 1.31 2004/06/23 13:48:20 z_stoichev
- * Added Chat support
- *
- * Revision 1.30 2004/06/22 14:32:09 z_stoichev
- * - Fixed Export file type filter misusage/order.
- * - Fixed Export contacts multiple headers (csv).
- * - Added Export contacts DisplayName field (csv).
- * - Added Import contacts status line feedback.
- * - Added Copy from Phonebook to SIM w/phone type.
- *
- * Revision 1.29 2004/06/19 11:15:22 z_stoichev
- * - Added Download entire phonebook.
- * - Changed Contact Group icons.
- *
- * Revision 1.28 2004/06/18 13:48:49 z_stoichev
- * - Fixed Do not lose personalization on sync.
- * - Added Contact DisplayName auto-update on Sync.
- * - Added Track edited contact in the list.
- *
- * Revision 1.27 2004/05/21 14:39:48 z_stoichev
- * Fixed Contact name changes not saved
- * Added Contact Display name support
- *
- * Revision 1.26 2004/05/21 10:09:05 z_stoichev
- * Changed logging handle routines.
- *
- * Revision 1.25 2004/05/19 18:34:16 z_stoichev
- * Build 0.1.0.35c
- *
- * Revision 1.24 2004/04/01 15:04:54 z_stoichev
- * New contact flag support
- *
- * Revision 1.23 2004/03/26 18:37:40 z_stoichev
- * Build 0.1.0.35 RC5
- *
- * Revision 1.22 2004/03/12 14:42:53 z_stoichev
- * Using new vCard code.
- * Download entire phonebook progress status.
- *
- * Revision 1.21 2004/03/09 15:02:28 z_stoichev
- * Use default contact GUID generator.
- * Offer to exchange home/cell on new phonebook.
- *
- * Revision 1.20 2004/03/07 21:57:43 z_stoichev
- * Synchroize re-coded from scratch.
- *
- * Revision 1.19 2004/01/28 17:39:53 z_stoichev
- * Popup menu rearranged.
- *
- * Revision 1.18 2004/01/13 12:29:04 z_stoichev
- * Fixed Phonebook not saved when empty.
- * Fixed Phonebook not sync Explorer view on Delete.
- * Fixed Synchronization Log events.
- * Fixed Export Contact to vCard, added missing LUID.
- * Changed Phonebook and Messages popup menu.
- * Added Import Contacts (vCard only).
- *
- * Revision 1.17 2003/12/16 17:40:07 z_stoichev
- * Columnt renamed to First and Last Name.
- * Fixed saving personalization data with spaces.
- *
- * Revision 1.16 2003/12/12 16:54:24 z_stoichev
- * Added view customization support.
- *
- * Revision 1.15 2003/12/02 16:35:52 z_stoichev
- * Memory leaks and other bugfixes for vCard.
- *
- * Revision 1.14 2003/12/01 16:03:12 z_stoichev
- * Support for Own card editing.
- *
- * Revision 1.13 2003/12/01 12:02:26 z_stoichev
- * Hit Enter shows properties window.
- *
- * Revision 1.12 2003/11/28 09:38:07 z_stoichev
- * Merged with branch-release-1-1 (Fma 0.10.28c)
- *
- * Revision 1.11.2.20 2003/11/27 12:55:04 z_stoichev
- * Sort list after Sync.
- *
- * Revision 1.11.2.19 2003/11/26 12:26:16 z_stoichev
- * Export to CSV fixed and default number export added.
- * Added Outlook 2003 support.
- *
- * Revision 1.11.2.18 2003/11/21 13:58:22 z_stoichev
- * Support for creating new contact with default cell number.
- *
- * Revision 1.11.2.17 2003/11/21 10:58:30 z_stoichev
- * Made SyncLog public method.
- *
- * Revision 1.11.2.16 2003/11/19 14:05:52 z_stoichev
- * Fixed vcf export of multiple items.
- *
- * Revision 1.11.2.15 2003/11/19 12:47:37 z_stoichev
- * Clear phonebook on Database load.
- *
- * Revision 1.11.2.14 2003/11/14 15:41:03 z_stoichev
- * Updates for patch 27d.
- *
- * Revision 1.11.2.13 2003/11/13 16:37:10 z_stoichev
- * Changed images.
- *
- * Revision 1.11.2.12 2003/11/12 16:21:08 z_stoichev
- * Allow contact properties from Explorer popup menu.
- *
- * Revision 1.11.2.11 2003/11/12 08:02:29 z_stoichev
- * Save data on refresh.
- *
- * Revision 1.11.2.10 2003/11/11 13:24:31 z_stoichev
- * Add personalization support.
- *
- * Revision 1.11.2.9 2003/11/10 14:03:11 z_stoichev
- * RC3
- *
- * Revision 1.11.2.8 2003/11/07 13:55:08 z_stoichev
- * Fixed delete new items.
- *
- * Revision 1.11.2.7 2003/11/07 11:15:23 z_stoichev
- * Add to group wizard added.
- * Right-click select.
- *
- * Revision 1.11.2.6 2003/11/06 16:13:37 z_stoichev
- * Popup menu changed.
- * Delete sanity chechs.
- * Can delete multiple items.
- *
- * Revision 1.11.2.5 2003/10/30 13:24:32 z_stoichev
- * Contact fileds restrictions saved to a file.
- * Fixed timeout error when modifying contact
- * in offline mode.
- *
- * Revision 1.11.2.4 2003/10/29 12:00:48 z_stoichev
- * Update explorer on contact change.
- *
- * Revision 1.11.2.3 2003/10/28 13:01:59 z_stoichev
- * Added default contact number usage.
- * Contact will not be marked as modified
- * if only custom Fma contact data is modified.
- *
- * Revision 1.11.2.2 2003/10/27 15:19:34 z_stoichev
- * Fixed: Contact was updated even if there aro no changes made.
- *
- * Revision 1.11.2.1 2003/10/27 07:22:54 z_stoichev
- * Build 0.1.0 RC1 Initial Checkin.
- *
- * Revision 1.11 2003/10/24 12:38:35 z_stoichev
- * Ask when deleting contact.
- * Hide unused splitter.
- * Fixed: list sort was not working.
- * Title length reduced.
- *
- * Revision 1.10 2003/10/23 11:51:28 z_stoichev
- * Edit/create contact uses external unit uEditContact.
- * Popup menu recreated.
- * Max fields length fixed.
- * Font changed.
- *
- * Revision 1.9 2003/10/22 13:07:38 z_stoichev
- * Make progress dialog optional.
- *
- * Revision 1.8 2003/10/16 11:15:40 z_stoichev
- * Use ConnProgress instead of SyncProgress, so
- * we can remove uSyncProgress.pas from project.
- * Show more detailed progress information.
- *
- * Revision 1.7 2003/10/14 07:25:04 z_stoichev
- * Show only one Sync Log window and
- * update log in realtime.
- *
- * Revision 1.6 2003/10/13 15:18:30 z_stoichev
- * Fixed Sync when contact is deleted on phone
- * and modified on PC. before it was failing with
- * "not found" error message.
- *
- * Revision 1.5 2003/10/13 14:16:22 z_stoichev
- * Modified to reflect changes in Obex methods.
- *
- * Revision 1.4 2003/10/10 13:18:48 z_stoichev
- * Sync speed up, refresh only on changes.
- * Progress diaglog is displayed.
- * No popup after sync.
- * Default message "No items to display..."
- *
- * Revision 1.3 2003/08/31 07:14:06 bufflig
- * Added vCard export of contacts.
- * Added handling of Name and Surname fields in contact edit so
- * that they are limited to 30 characters together instead of 15 each.
- * Made vCard be reused throughout the form, created once in
- * constructor and destroyed in destructor.
- *
- * Revision 1.2 2003/07/02 12:35:48 crino77
- * Automatic refresh after sync
- * popup at the end of sync
- * removed keypress on number fields
- * added handle exception on sync aborted
- * added export contact's list
- * added force update
- * added force new contact to restore phonebook
- * added unicode support in textbox
- *
- * Revision 1.1 2003/02/14 14:25:33 crino77
- * Initial Checkin
- *
- *
- *
- *******************************************************************************
- }
-
- interface
-
- uses
- Windows, Messages, SysUtils, StrUtils,Classes, Graphics, Controls, Forms, Dialogs,
- Menus, ImgList, VirtualTrees, ExtCtrls, StdCtrls, TntStdCtrls, TntClasses, ActnList,
- uVcard, uPromptConflict, uSyncLog, Mask, Placemnt;
-
- type
- TNumberPos = Record
- home, work, cell, fax, other : integer;
- end;
- TContactData = Record
- title, name, surname, displayname, org, email: WideString;
- home, work, cell, fax, other : WideString;
- CDID: TGUID;
- LUID : WideString;
- StateIndex : Integer; //0 new entry;1 modified entry;2 deleted entry;3 normal entry
- DefaultIndex: Integer; //0 none;1 cell;2 work;3 home;4 other
- Position: TNumberPos;
- picture, sound: WideString;
- end;
- PContactData = ^TContactData;
-
- TfrmSyncPhonebook = class(TFrame)
- Panel1: TPanel;
- ListContacts: TVirtualStringTree;
- btnSYNC: TButton;
- Panel2: TPanel;
- btnLOG: TButton;
- PopupMenu1: TPopupMenu;
- ForceUpdate: TMenuItem;
- Exportselectedcontacts1: TMenuItem;
- N1: TMenuItem;
- ForceNewContact: TMenuItem;
- NoItemsPanel: TPanel;
- N2: TMenuItem;
- Properties1: TMenuItem;
- N3: TMenuItem;
- NewContact1: TMenuItem;
- Delete1: TMenuItem;
- N4: TMenuItem;
- N5: TMenuItem;
- AddtoGroup1: TMenuItem;
- txtCC: TEdit;
- txtLUID: TEdit;
- UndoLastChange1: TMenuItem;
- SendMsg1: TMenuItem;
- voicecall1: TMenuItem;
- FormStorage1: TFormStorage;
- ImportContacts1: TMenuItem;
- OpenDialog1: TOpenDialog;
- ClearChangedFlag1: TMenuItem;
- N6: TMenuItem;
- PopupMenu2: TPopupMenu;
- FirstLast1: TMenuItem;
- LastFirst1: TMenuItem;
- N7: TMenuItem;
- DownloadEntirePhonebook1: TMenuItem;
- ChatContact1: TMenuItem;
- //List
- procedure ListContactsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
- Column: TColumnIndex; TextType: TVSTTextType;
- var CellText: WideString);
- procedure ListContactsCompareNodes(Sender: TBaseVirtualTree; Node1,
- Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
- procedure ListContactsHeaderClick(Sender: TVTHeader; Column: TColumnIndex;
- Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- procedure ListContactsGetImageIndex(Sender: TBaseVirtualTree;
- Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
- var Ghosted: Boolean; var ImageIndex: Integer);
- procedure btnEditClick(Sender: TObject);
- //Button
- procedure btnNEWClick(Sender: TObject);
- procedure btnDELClick(Sender: TObject);
- procedure btnSYNCClick(Sender: TObject);
- procedure btnLOGClick(Sender: TObject);
- procedure ForceUpdateClick(Sender: TObject);
- procedure ForceNewContactClick(Sender: TObject);
- procedure ListContactsAfterPaint(Sender: TBaseVirtualTree;
- TargetCanvas: TCanvas);
- procedure PopupMenu1Popup(Sender: TObject);
- procedure AddToGroupClick(Sender: TObject);
- procedure UndoLastChange1Click(Sender: TObject);
- procedure ListContactsIncrementalSearch(Sender: TBaseVirtualTree;
- Node: PVirtualNode; const SearchText: WideString;
- var Result: Integer);
- procedure ListContactsKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- procedure ImportContacts1Click(Sender: TObject);
- procedure ClearChangedFlag1Click(Sender: TObject);
- procedure FirstLast1Click(Sender: TObject);
- procedure DownloadEntirePhonebook1Click(Sender: TObject);
- procedure FormStorage1SavePlacement(Sender: TObject);
- procedure FormStorage1RestorePlacement(Sender: TObject);
- procedure ListContactsHeaderMouseUp(Sender: TVTHeader;
- Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- private
- FSyncConflict: Integer;
- VCard: TVCard;
- CC: WideString;
- FUndoEdit: TContactData;
- FUndoIndx: cardinal;
- function Synchronize: boolean;
- function FullRefresh: boolean;
- function CheckInArray(A: array of widestring; S: Widestring): boolean;
- // procedure ResetInArray(var A: array of widestring; S: Widestring);
- function EraseContact(LUID :Widestring; Log :Boolean = True):Boolean;
- function LFindContact(LUID :Widestring; var AContact: PContactData):Boolean;
- function PromptConflict(NameContact: WideString; Info:WideString): boolean;
- function GetPhoneCapacity: Integer;
- procedure ForceContact(State: integer);
- procedure DoFirstImportCheck;
- public
- State: Integer;
- SelContact: PContactData;
- FMaxRecME,FMaxNameLen,FMaxTitleLen,FMaxOrgLen,FMaxMailLen,FMaxTellen: cardinal;
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure SyncLog(Desc: WideString);
- procedure RenderListView(const sl: TStrings);
- procedure RenderGUIDs;
- procedure SaveContacts(FileName:WideString);
- procedure LoadContacts(FileName:WideString);
- procedure ExportList(FileType:Integer; Filename: WideString);
- procedure OnConnected;
- function IsUniqueGUID(who: PContactData): boolean;
- function UpdatePositions: boolean;
- function FindContact(Number: WideString): WideString; overload;
- function FindContact(FullName: WideString; var AContact: PContactData): boolean; overload;
- function FindContact(FullName: WideString; var ANode: PVirtualNode): boolean; overload;
- { Edit contact. NewNumber and ContactData are for external (not Phonebook) contacts, as Own card, and
- SIM contacts editing. NewNumber is default mobile number when creating new contact. }
- function DoEdit(AsNew: boolean = False; NewNumber: string = ''; ContactData: PContactData = nil): boolean;
- end;
-
- function NewGUID: TGUID;
-
- function MigrateContact(OldContact: PContactData; var NewContact: PContactData): boolean;
-
- function vCard2Contact(VCard: TVCard; contact: PContactData): boolean;
- function Contact2vCard(contact: PContactData; var VCard: TVCard): boolean;
-
- function NumPos2Str(Pos: TNumberPos): string;
- function NumPosEmpty(contact: PContactData): boolean;
-
- function GetvCardFullName(VCard: TVCard): WideString;
-
- function GetContactDisplayName(contact: PContactData; FamilyFirst: boolean = False): WideString;
- function GetContactFullName(contact: PContactData; FamilyFirst: boolean = False): WideString;
- procedure SetContactFullName(contact: PContactData; FullName: WideString);
- function GetContactDefPhone(contact: PContactData): string;
- function GetContactPictureFile(contact: PContactData): string;
- function GetContactSoundFile(contact: PContactData): string;
-
- function GetContactFmaid(contact: PContactData): string;
- function GetContactNotes(contact: PContactData; Notes: TTntStrings): boolean;
- function SetContactNotes(contact: PContactData; Notes: TTntStrings): boolean;
- function GetContactDetails(contact: PContactData; Notes: TTntStrings): boolean;
-
- function IsContactPhone(contact: PContactData; Phone: string): boolean;
- function GetContactPhoneType(contact: PContactData; Phone: string): string;
- function ReplaceContactDefPhone(contact: PContactData; Phone: string): string;
-
- function ContactDefPosition(contact: PContactData; SetPosition: integer = -1): integer;
- function GetContactPosition(contact: PContactData; Phone: string): integer;
- procedure SetContactPosition(contact: PContactData; Phone: string; SetPosition: integer);
-
- implementation
-
- {$R *.dfm}
-
- { Utils }
-
- uses WebUtil, DateUtils, Unicode, Unit1, uGlobal, uConnProgress, uEditContact,
- ComCtrls, TntComCtrls, uAddToGroup, uStatusDlg, IniFiles, uDebug, uXML;
-
- function NewGUID: TGUID;
- begin
- CreateGUID(Result);
- end;
-
- function IsContactPhone(contact: PContactData; Phone: string): boolean;
- var
- a,b: string;
- begin
- Result := False;
- a := Form1.GetPartialNumber(Phone);
- with contact^ do begin
- b := Form1.GetPartialNumber(cell);
- if a = b then begin
- Result := True;
- exit;
- end;
- b := Form1.GetPartialNumber(work);
- if a = b then begin
- Result := True;
- exit;
- end;
- b := Form1.GetPartialNumber(home);
- if a = b then begin
- Result := True;
- exit;
- end;
- b := Form1.GetPartialNumber(fax);
- if a = b then begin
- Result := True;
- exit;
- end;
- b := Form1.GetPartialNumber(other);
- if a = b then begin
- Result := True;
- end;
- end;
- end;
-
- { This will update DisplayName according to changes in NewContact and settings in OldContact,
- and all other FMA specific settings }
- function MigrateContact(OldContact: PContactData; var NewContact: PContactData): boolean;
- begin
- with TfrmEditContact.Create(nil) do
- try
- contact := OldContact^;
- LoadAndMergeWith(NewContact^);
- { Migrate contact Fma internal settings }
- NewContact^.displayname := txtDisplayAs.Text; // get newly generated display name
- NewContact^.DefaultIndex := OldContact^.DefaultIndex;
- NewContact^.sound := OldContact^.sound;
- NewContact^.picture := OldContact^.picture;
- NewContact^.CDID := OldContact^.CDID;
- // - Do not copy old LUID sync id //NewContact^.LUID := OldContact^.LUID;
- // - Do not copy old phone positions //NewContact^.Position := OldContact^.Position;
- Result := True;
- finally
- Free;
- end;
- end;
-
- function GetContactFmaid(contact: PContactData): string;
- begin
- Result := Format('{%s}-%s',[contact^.LUID,GUIDToString(contact^.CDID)]);
- end;
-
- function GetContactDetails(contact: PContactData; Notes: TTntStrings): boolean;
- var
- s: string;
- begin
- Notes.Clear;
- case contact^.StateIndex of
- 0: s := 'New';
- 1: s := 'Modified';
- 2: s := 'Deleted';
- 3: s := 'Unmodified';
- end;
- Notes.Add('State: '+s+' contact');
- Notes.Add('Full name: '+getcontactfullname(contact));
- Notes.Add('Display name: '+contact^.displayname);
- Notes.Add('Title: '+contact^.title);
- Notes.Add('Company: '+contact^.org);
- Notes.Add('E-mail: '+contact^.email);
- Notes.Add('Home phone: '+contact^.home);
- Notes.Add('Work phone: '+contact^.work);
- Notes.Add('Cell phone: '+contact^.cell);
- Notes.Add('Fax number: '+contact^.fax);
- Notes.Add('Other phone: '+contact^.other);
- Notes.Add('Picture File: '+contact^.picture);
- Notes.Add('Ringing Tone: '+contact^.sound);
- case contact^.DefaultIndex of
- 0: s := 'None';
- 1: s := 'Cell';
- 2: s := 'Work';
- 3: s := 'Home';
- 4: s := 'Other';
- end;
- Notes.Add('Default phone: '+s);
- Result := True;
- end;
-
- function GetContactNotes(contact: PContactData; Notes: TTntStrings): boolean;
- var
- DBName,Section: string;
- sl: TStringList;
- i: integer;
- begin
- Section := GetContactFmaid(contact);
- DBName := Form1.GetDatabasePath+'CallNotes.dat';
- if not FileExists(DBName) then
- with TFileStream.Create(DBName,fmCreate) do Free;
- with TIniFile.Create(DBName) do
- try
- sl := TStringList.Create;
- try
- ReadSection(Section,sl);
- Notes.Clear;
- for i := 0 to sl.Count-1 do
- Notes.Add(ReadString(Section,sl[i],''));
- finally
- sl.Free;
- end;
- Result := True;
- finally
- Free;
- end;
- end;
-
- function SetContactNotes(contact: PContactData; Notes: TTntStrings): boolean;
- var
- DBName,Section: string;
- i: integer;
- begin
- Section := GetContactFmaid(contact);
- DBName := Form1.GetDatabasePath+'CallNotes.dat';
- if not FileExists(DBName) then
- with TFileStream.Create(DBName,fmCreate) do Free;
- with TIniFile.Create(DBName) do
- try
- EraseSection(Section);
- for i := 0 to Notes.Count-1 do
- WriteString(Section,IntToStr(i),Notes[i]);
- Result := True;
- finally
- Free;
- end;
- end;
-
- function vCard2Contact(VCard: TVCard; contact: PContactData): boolean;
- var
- sl: TTntStringList;
- begin
- Result := True;
- FillChar(contact^,SizeOf(contact^),0);
- contact^.title := VCard.title;
- contact^.name := VCard.name;
- contact^.surname := VCard.surname;
- contact^.displayname := VCard.DisplayName;
- contact^.org := VCard.org;
- contact^.email := VCard.email;
- contact^.home := VCard.telhome;
- contact^.work := VCard.telwork;
- contact^.cell := VCard.telcell;
- contact^.fax := VCard.telfax;
- contact^.other := VCard.telother;
- // DefaultIndex = 0 none;1 cell;2 work;3 home;4 other
- if VCard.TelPref = 'M' then
- contact^.DefaultIndex := 1
- else if VCard.TelPref = 'W' then
- contact^.DefaultIndex := 2
- else if VCard.TelPref = 'H' then
- contact^.DefaultIndex := 3
- else if VCard.TelPref = 'O' then
- contact^.DefaultIndex := 4;
- contact^.LUID := VCard.LUID;
- try
- if VCard.UID <> '' then
- contact.CDID := StringToGUID('{'+VCard.UID+'}')
- else
- contact.CDID := NewGUID;
- except
- contact.CDID := NewGUID;
- end;
- sl := TTntStringList.Create;
- try
- sl.Text := VCard.Notes;
- SetContactNotes(contact,sl);
- finally
- sl.Free;
- end;
- end;
-
- function Contact2vCard(contact: PContactData; var VCard: TVCard): boolean;
- var
- sl: TTntStringList;
- begin
- Result := True;
- VCard.Clear;
- VCard.title := contact^.title;
- VCard.name := contact^.name;
- VCard.surname := contact^.surname;
- VCard.DisplayName := contact^.displayname;
- VCard.org := contact^.org;
- VCard.email := contact^.email;
- VCard.telhome := contact^.home;
- VCard.telwork := contact^.work;
- VCard.telcell := contact^.cell;
- VCard.telfax := contact^.fax;
- VCard.telother := contact^.other;
- // DefaultIndex = 0 none;1 cell;2 work;3 home;4 other
- case contact^.DefaultIndex of
- 1: VCard.TelPref := 'M';
- 2: VCard.TelPref := 'W';
- 3: VCard.TelPref := 'H';
- 4: VCard.TelPref := 'O';
- end;
- VCard.LUID := contact^.LUID;
- try
- VCard.UID := GUIDToString(contact^.CDID);
- except
- VCard.UID := GUIDToString(NewGUID);
- end;
- { remove TGUID brackets }
- if (length(VCard.UID) > 1) and (VCard.UID[1] = '{') then begin
- Delete(VCard.UID,1,1); // {
- Delete(VCard.UID,length(VCard.UID),1); // }
- end;
- sl := TTntStringList.Create;
- try
- GetContactNotes(contact,sl);
- VCard.Notes := sl.Text;
- finally
- sl.Free;
- end;
- { TODO: Add better Modified date support }
- VCard.ModifiedDate := Now;
- //debug
- if Form1.Memo2.Visible then begin
- Form1.Memo2.Lines.Clear;
- Form1.Memo2.Lines.AddStrings(VCard.Raw);
- end;
- end;
-
- function NumPos2Str(Pos: TNumberPos): string;
- begin
- Result := IntToStr(Pos.home) + ',' + IntToStr(Pos.work) +
- ',' + IntToStr(Pos.cell) + ',' + IntToStr(Pos.fax) +
- ',' + IntToStr(Pos.other);
- end;
-
- function NumPosEmpty(contact: PContactData): boolean;
- begin
- Result := ((contact.Position.home = 0) and (contact.home <> '')) or
- ((contact.Position.work = 0) and (contact.work <> '')) or
- ((contact.Position.cell = 0) and (contact.cell <> '')) or
- ((contact.Position.fax = 0) and (contact.fax <> '')) or
- ((contact.Position.other = 0) and (contact.other <> ''));
- end;
-
- function GetContactPictureFile(contact: PContactData): string;
- var
- s: string;
- begin
- s := '';
- if contact.picture <> '' then begin
- s := ExePath+'data\'+Form1.PhoneIdentity+'\pic\'+contact.picture;
- if not FileExists(s) then s := '';
- end;
- Result := s;
- end;
-
- function GetContactSoundFile(contact: PContactData): string;
- var
- s: string;
- begin
- s := '';
- if contact.sound <> '' then begin
- s := ExePath+'data\'+Form1.PhoneIdentity+'\snd\'+contact.sound;
- if not FileExists(s) then s := '';
- end;
- Result := s;
- end;
-
- function GetvCardFullName(VCard: TVCard): WideString;
- begin
- with VCard do begin
- Result := name;
- if surname <> '' then Result := Result + ' ' + surname;
- end;
- end;
-
- function GetContactDisplayName(contact: PContactData; FamilyFirst: boolean = False): WideString;
- var
- s: WideString;
- begin
- s := Trim(contact^.displayname);
- if s = '' then s := GetContactFullName(contact,FamilyFirst);
- Result := s;
- end;
-
- function GetContactFullName(contact: PContactData; FamilyFirst: boolean): WideString;
- begin
- with contact^ do begin
- if FamilyFirst then begin
- Result := surname;
- if name <> '' then Result := Result + ' ' + name;
- end
- else begin
- Result := name;
- if surname <> '' then Result := Result + ' ' + surname;
- end;
- end;
- Result := Trim(Result);
- end;
-
- procedure SetContactFullName(contact: PContactData; FullName: WideString);
- var
- i,j: integer;
- begin
- with contact^ do begin
- j := Length(FullName);
- i := j;
- while (i <> 0) and (FullName[i] <> ' ') do dec(i);
- if i = 0 then i := j+1;
- name := Copy(FullName,1,i-1);
- surname := Copy(FullName,i+1,j);
- end;
- end;
-
- function GetContactPosition(contact: PContactData; Phone: string): integer;
- begin
- Result := -1;
- with contact^ do begin
- if home = Phone then Result := Position.home;
- if work = Phone then Result := Position.work;
- if cell = Phone then Result := Position.cell;
- if fax = Phone then Result := Position.fax;
- if other = Phone then Result := Position.other;
- end;
- end;
-
- procedure SetContactPosition(contact: PContactData; Phone: string; SetPosition: integer);
- begin
- with contact^ do begin
- if home = Phone then Position.home := SetPosition;
- if work = Phone then Position.work := SetPosition;
- if cell = Phone then Position.cell := SetPosition;
- if fax = Phone then Position.fax := SetPosition;
- if other = Phone then Position.other := SetPosition;
- end;
- end;
-
- function ContactDefPosition(contact: PContactData; SetPosition: integer): integer;
- procedure FindFirstGood;
- begin
- with contact^ do begin
- if cell <> '' then begin
- if SetPosition > 0 then Position.cell := SetPosition;
- if Position.cell > 0 then Result := Position.cell;
- end else
- if work <> '' then begin
- if SetPosition > 0 then Position.work := SetPosition;
- if Position.work > 0 then Result := Position.work;
- end else
- if home <> '' then begin
- if SetPosition > 0 then Position.home := SetPosition;
- if Position.home > 0 then Result := Position.home;
- end else
- if other <> '' then begin
- if SetPosition > 0 then Position.other := SetPosition;
- if Position.other > 0 then Result := Position.other;
- end;
- end;
- end;
- begin
- Result := -1;
- with contact^ do case DefaultIndex of
- 1: if cell <> '' then begin
- if SetPosition > 0 then Position.cell := SetPosition;
- if Position.cell > 0 then Result := Position.cell;
- end;
- 2: if work <> '' then begin
- if SetPosition > 0 then Position.work := SetPosition;
- if Position.work > 0 then Result := Position.work;
- end;
- 3: if home <> '' then begin
- if SetPosition > 0 then Position.home := SetPosition;
- if Position.home > 0 then Result := Position.home;
- end;
- 4: if other <> '' then begin
- if SetPosition > 0 then Position.other := SetPosition;
- if Position.other > 0 then Result := Position.other;
- end;
- end;
- if Result = -1 then FindFirstGood;
- end;
-
- function GetContactDefPhone(contact: PContactData): string;
- procedure FindFirstNumber;
- begin
- with contact^ do begin
- if cell <> '' then begin
- Result := cell;
- end else
- if work <> '' then begin
- Result := work;
- end else
- if home <> '' then begin
- Result := home;
- end else
- if other <> '' then begin
- Result := other;
- end;
- end;
- end;
- begin
- Result := '';
- with contact^ do case DefaultIndex of
- 1: Result := cell;
- 2: Result := work;
- 3: Result := home;
- 4: Result := other;
- end;
- if Result = '' then FindFirstNumber;
- end;
-
- function ReplaceContactDefPhone(contact: PContactData; Phone: string): string;
- procedure FindFirstNumber;
- begin
- with contact^ do begin
- if cell <> '' then begin
- cell := Phone;
- end else
- if work <> '' then begin
- work := Phone;
- end else
- if home <> '' then begin
- home := Phone;
- end else
- if other <> '' then begin
- other := Phone;
- end;
- end;
- end;
- begin
- Result := GetContactDefPhone(contact);
- with contact^ do case DefaultIndex of
- 1: cell := Phone;
- 2: work := Phone;
- 3: home := Phone;
- 4: other := Phone;
- else FindFirstNumber;
- end;
- end;
-
- function GetContactPhoneType(contact: PContactData; Phone: string): string;
- begin
- Result := '';
- with contact^ do begin
- if cell = Phone then begin
- Result := 'M';
- end else
- if work = Phone then begin
- Result := 'W';
- end else
- if home = Phone then begin
- Result := 'H';
- end else
- if fax = Phone then begin
- Result := 'F';
- end else
- if other = Phone then begin
- Result := 'O';
- end;
- end;
- end;
-
- { TfrmSyncPhonebook }
-
- constructor TfrmSyncPhonebook.Create(AOwner: TComponent);
- begin
- inherited;
- VCard := TVCard.Create;
- FMaxRecME := 510; FMaxNameLen := 180; FMaxTelLen := 80;
- end;
-
- destructor TfrmSyncPhonebook.Destroy;
- begin
- VCard.Free;
- inherited;
- end;
-
- procedure TfrmSyncPhonebook.ListContactsGetText(Sender: TBaseVirtualTree;
- Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
- var CellText: WideString);
- var
- contact: PContactData;
- begin
- contact := Sender.GetNodeData(Node);
-
- if Column = 0 then
- case contact.StateIndex of //0 new entry;1 modified entry;2 deleted entry;3 normal entry
- 0: CellText := 'New';
- 1: CellText := 'Mod';
- 2: CellText := 'Del';
- else CellText := '';
- end
- else if Column = 1 then CellText := GetContactDisplayName(contact,LastFirst1.Checked)
- else if Column = 2 then CellText := contact.title
- else if Column = 3 then CellText := contact.org
- else if Column = 4 then CellText := contact.email
- else if Column = 5 then CellText := contact.home
- else if Column = 6 then CellText := contact.work
- else if Column = 7 then CellText := contact.cell
- else if Column = 8 then CellText := contact.fax
- else if Column = 9 then CellText := contact.other
- end;
-
- procedure TfrmSyncPhonebook.ListContactsHeaderClick(Sender: TVTHeader;
- Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
- Y: Integer);
- begin
- if Button = mbLeft then begin
- if Column = Sender.SortColumn then begin
- if Sender.SortDirection = sdDescending then
- Sender.SortDirection := sdAscending
- else
- Sender.SortDirection := sdDescending;
- end
- else
- Sender.SortColumn := Column;
- ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection);
- end;
- end;
-
- procedure TfrmSyncPhonebook.ListContactsCompareNodes(Sender: TBaseVirtualTree;
- Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
- var
- contact1, contact2: PContactData;
- begin
- contact1 := Sender.GetNodeData(Node1);
- contact2 := Sender.GetNodeData(Node2);
-
- if Column = 0 then begin
- if contact1.StateIndex > contact2.StateIndex then
- Result := 1
- else
- if contact1.StateIndex < contact2.StateIndex then
- Result := -1
- else
- Result := 0;
- end
- else if Column = 1 then
- Result := WideCompareStr(GetContactDisplayName(contact1,LastFirst1.Checked),
- GetContactDisplayName(contact2,LastFirst1.Checked))
- else if Column = 2 then Result := WideCompareStr(contact1.title, contact2.title)
- else if Column = 3 then Result := WideCompareStr(contact1.org, contact2.org)
- else if Column = 4 then Result := WideCompareStr(contact1.email, contact2.email)
- else if Column = 5 then Result := WideCompareStr(contact1.home, contact2.home)
- else if Column = 6 then Result := WideCompareStr(contact1.work, contact2.work)
- else if Column = 7 then Result := WideCompareStr(contact1.cell, contact2.cell)
- else if Column = 8 then Result := WideCompareStr(contact1.fax, contact2.fax)
- else if Column = 9 then Result := WideCompareStr(contact1.other, contact2.other)
- end;
-
- procedure TfrmSyncPhonebook.ListContactsGetImageIndex(Sender: TBaseVirtualTree;
- Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
- var Ghosted: Boolean; var ImageIndex: Integer);
- var
- contact: PContactData;
- begin
- if Column = 0 then begin
- if (Kind = ikNormal) or (Kind = ikSelected) then begin
- contact := Sender.GetNodeData(Node);
- { Yesllow icon on personalized contacts, blue on others }
- if (contact.StateIndex = 3) and ((contact.picture <> '') or (contact.sound <> '')) then
- ImageIndex := 4
- else
- ImageIndex := contact.StateIndex;
- end
- else ImageIndex := -1;
- end;
- end;
-
- procedure TfrmSyncPhonebook.btnEditClick(Sender: TObject);
- var
- Node :PVirtualNode;
- begin
- Node := ListContacts.FocusedNode;
- if Node <> nil then begin
- Selcontact := ListContacts.GetNodeData(Node);
- FUndoIndx := Node.Index;
- txtLUID.Text := Selcontact.LUID + ' - ' + inttostr(Selcontact.StateIndex);
- DoEdit;
- end;
- end;
-
- procedure TfrmSyncPhonebook.RenderListView(const sl: TStrings);
- var
- i: Integer;
- contact: PContactData;
- Node: PVirtualNode;
- s: String;
- begin
- ListContacts.BeginUpdate;
- try
- ListContacts.Clear;
- ListContacts.NodeDataSize := sizeof(TContactData);
- i := 0;
- while i < sl.Count do begin
- s := sl.Strings[i];
- while (not EvenQuotes(s)) and (i < sl.Count - 2) do begin
- Inc(i);
- s := s + #13#10 + sl.Strings[i];
- end;
-
- if Pos('LOG:', s) = 1 then begin
- CC := Copy(s, Pos(':', s) + 1, length(s));
- txtCC.Text := CC;
- Break;
- end;
- Node := ListContacts.AddChild(nil);
- contact := ListContacts.GetNodeData(Node);
- try
- { Enter data }
- contact.title := HTMLDecode(GetToken(s,1));
- contact.name := HTMLDecode(GetToken(s,2));
- contact.surname := HTMLDecode(GetToken(s,3));
- contact.org := HTMLDecode(GetToken(s,4));
- contact.email := HTMLDecode(GetToken(s,5));
- contact.home := HTMLDecode(GetToken(s,6));
- contact.work := HTMLDecode(GetToken(s,7));
- contact.cell := HTMLDecode(GetToken(s,8));
- contact.fax := HTMLDecode(GetToken(s,9));
- contact.other := HTMLDecode(GetToken(s,10));
- contact.LUID := GetToken(s,11);
- contact.stateindex := strtoint(GetToken(s,0));
- { Get number positions }
- FillChar(contact.Position,SizeOf(contact.Position),0);
- contact.Position.home := StrToInt(GetToken(s,12));
- contact.Position.work := StrToInt(GetToken(s,13));
- contact.Position.cell := StrToInt(GetToken(s,14));
- contact.Position.fax := StrToInt(GetToken(s,15));
- contact.Position.other := StrToInt(GetToken(s,16));
- { Get default number }
- contact.DefaultIndex := StrToInt(GetToken(s,17));
- { Get personalization }
- contact.picture := HTMLDecode(GetToken(s,18));
- contact.sound := HTMLDecode(GetToken(s,19));
- try
- { Outlook sync ID field }
- contact.CDID := StringToGUID(GetToken(s,20));
- except
- contact.CDID := NewGUID;
- end;
- { Display Name }
- contact.displayname := HTMLDecode(GetToken(s,21));
- except
- on E: Exception do
- Form1.Debug('CONTACTS SYNC DB ERROR (' + E.Message + '): '+s);
- end;
-
- Inc(i);
- end;
- RenderGUIDs;
- finally
- ListContacts.EndUpdate;
- ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection);
- ListContacts.Update;
- UndoLastChange1.Enabled := False;
- end;
- end;
-
- procedure TfrmSyncPhonebook.SaveContacts(FileName:WideString);
- var
- sl: TStrings;
- Node: PVirtualNode;
- contact: PContactData;
- str: String;
- begin
- sl := TStringList.Create;
- try
- with ListContacts do begin
- Node := GetFirst;
- if Node <> nil then repeat
- try
- contact := GetNodeData(node);
- str := inttostr(contact.StateIndex);
- str := str + ',"' + HTMLEncode(contact.title,False);
- str := str + '","' + HTMLEncode(contact.name,False);
- str := str + '","' + HTMLEncode(contact.surname,False);
- str := str + '","' + HTMLEncode(contact.org,False);
- str := str + '","' + HTMLEncode(contact.email,False);
- str := str + '","' + HTMLEncode(contact.home,False);
- str := str + '","' + HTMLEncode(contact.work,False);
- str := str + '","' + HTMLEncode(contact.cell,False);
- str := str + '","' + HTMLEncode(contact.fax,False);
- str := str + '","' + HTMLEncode(contact.other,False);
- str := str + '",' + contact.LUID;
- str := str + ',' + NumPos2Str(contact.Position);
- str := str + ',' + IntToStr(contact.DefaultIndex);
- str := str + ',"' + HTMLEncode(contact.picture,False);
- str := str + '","' + HTMLEncode(contact.sound,False);
- str := str + '",' + GUIDToString(contact.CDID);
- str := str + ',"' + HTMLEncode(contact.displayname,False) + '"';
- sl.Add(str);
- except
- end;
- Node := GetNext(Node);
- until Node = nil;
- end;
- sl.add('LOG:' + CC);
- sl.SaveToFile(FileName);
- sl.Clear;
- sl.Add(IntToStr(FMaxRecME));
- sl.Add(IntToStr(FMaxNameLen));
- sl.Add(IntToStr(FMaxTitleLen));
- sl.Add(IntToStr(FMaxOrgLen));
- sl.Add(IntToStr(FMaxMailLen));
- sl.Add(IntToStr(FMaxTellen));
- sl.SaveToFile(ChangeFileExt(FileName,'MAX.dat'));
- finally
- sl.Free;
- end;
- end;
-
- procedure TfrmSyncPhonebook.LoadContacts(FileName:WideString);
- var
- sl : TStringList;
- begin
- ListContacts.NodeDataSize := sizeof(TContactData);
- //Force primary sort column ... i don't why!??!
- //ListContacts.Header.SortColumn := 1;
- sl := TStringList.Create;
- try
- try
- sl.LoadFromFile(FileName);
- except
- end;
- RenderListView(sl);
- FMaxRecME := 510;
- FMaxNameLen := 30;
- FMaxTitleLen := 15;
- FMaxOrgLen := 15;
- FMaxMailLen := 50;
- FMaxTellen := 40;
- try
- sl.LoadFromFile(ChangeFileExt(FileName,'MAX.dat'));
- FMaxRecME := StrToInt(sl[0]);
- FMaxNameLen := StrToInt(sl[1]);
- FMaxTitleLen := StrToInt(sl[2]);
- FMaxOrgLen := StrToInt(sl[3]);
- FMaxMailLen := StrToInt(sl[4]);
- FMaxTellen := StrToInt(sl[5]);
- except
- end;
- finally
- sl.Free;
- end;
- end;
-
- procedure TfrmSyncPhonebook.btnSYNCClick(Sender: TObject);
- var
- isModified: Boolean;
- dlg: TfrmConnect;
- begin
- FSyncConflict := Form1.FSyncConflict;
-
- btnSync.Enabled := False;
- Form1.ActionSyncPhonebook.Enabled := False;
-
- dlg := GetProgressDialog;
- try
- if Form1.CanShowProgress then
- dlg.ShowProgress(Form1.FProgressLongOnly);
- dlg.SetDescr('Synchronizing phonebook contacts');
- Form1.Status('Start Sync Phonebook....');
- SyncLog('Sync Phonebook started.');
- VCard.clear;
- try
- //Start the sync process
- isModified := Synchronize;
- //Force refresh phoneBook
- if isModified then begin
- dlg.SetDescr('Refreshing local phonebook');
- Form1.RefreshPhoneBook;
- end;
- //ShowMessage('Sync Phonebook completed');
- Form1.Status('Sync Phonebook completed.');
- SyncLog('Sync Phonebook completed.');
- except
- ShowMessage('Error: synchronize aborted');
- SyncLog('Error: synchronize aborted');
- end;
- finally
- FreeProgressDialog;
- btnSync.Enabled := True;
- ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection);
- ListContacts.Update;
- Form1.UpdateMEPhonebook;
- Form1.ActionSyncPhonebook.Enabled := True;
- end;
- end;
-
- procedure TfrmSyncPhonebook.btnNEWClick(Sender: TObject);
- begin
- if ListContacts.ChildCount[nil] >= FMaxRecME then begin
- ShowMessage('No more space in pb memory!' + #13 + #10 + 'I''m sorry.');
- Exit;
- end;
- DoEdit(True);
- end;
-
- procedure TfrmSyncPhonebook.btnDELClick(Sender: TObject);
- var
- Node,Tmp: PVirtualNode;
- contact :PContactData;
- oldState :Integer;
- s: string;
- begin
- if ListContacts.SelectedCount = 0 then exit;
- s := 'Deleting ' + IntToStr(ListContacts.SelectedCount) + ' item(s)';
- if MessageDlg(s+'. Do you wish to continue?',mtConfirmation,[mbYes,mbNo],0) <> ID_YES then
- exit;
- Form1.Status(s+'...');
- State := 2;
- ListContacts.BeginUpdate;
- try
- node := ListContacts.GetFirst;
- while node <> nil do begin
- if ListContacts.Selected[node] then begin
- contact := ListContacts.GetNodeData(Node);
- oldState := contact.stateindex;
- contact.stateindex := State;
- if oldState = 0 then begin
- Tmp := Node;
- if Node <> ListContacts.GetFirst then begin
- Node := ListContacts.GetPrevious(Node);
- ListContacts.DeleteNode(Tmp);
- end
- else begin
- ListContacts.DeleteNode(Tmp);
- Node := ListContacts.GetFirst;
- continue;
- end;
- end;
- end;
- node := ListContacts.GetNext(Node);
- end;
- finally
- ListContacts.EndUpdate;
- Form1.Status('');
- Form1.UpdateMEPhonebook;
- end;
- end;
-
- function TfrmSyncPhonebook.Synchronize: boolean; // True if any change is made!
- var
- sl,pl: TStringList;
- stream : TStream;
- addPCont : array of widestring;
- delPCont : array of widestring;
- j: Integer;
- Node: PVirtualNode;
- migrate: TContactData;
- contact: PContactData;
- F,LUID : WideString;
- PhoneOnPc,AsNew: Boolean;
- begin
- Result := False;
- if ListContacts.childcount[nil] = 0 then begin
- Result := FullRefresh;
- exit;
- end;
-
- //start sync process
- Form1.ObexConnect('IRMC-SYNC');
- if not Form1.FConnected then begin
- ShowMessage('The Sync Phonebook can''t start...try to restart your phone.');
- SyncLog('The Sync Phonebook can''t start...try to restart your phone.');
- btnSync.Enabled := True;
- Form1.ActionSyncPhonebook.Enabled := True;
- Exit;
- end;
-
- VCard.Clear;
- sl := TStringList.Create;
- pl := TStringList.Create;
- try
- { if Fma CC is 1020, and phone CC is 1025 the result might be like this:
- (here for example, we have 3 new and one deleted contacts)
-
- SN:351956003653753
- DID:6D25
- Total-Records:100
- Maximum-Records:510
- M:1022::00003D010000
- M:1023::000047010000
- H:1024::0000E4000000
- M:1025::0000E5000000
- }
- //Get all record changes in phone for latest used LOG Number in FMA
- Form1.ObexGetObject('telecom/pb/luid/' + CC +'.log',pl);
-
- // Build lists of localy modified and deleted contacts (on PC)
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- contact := ListContacts.GetNodeData(node);
- case contact.StateIndex of
- 0,1: begin // new or modified
- SetLength(addPCont, length(addPCont) + 1);
- addPCont[High(addPCont)] := contact.LUID;
- end;
- 2: begin// deleted
- SetLength(delPCont, length(delPCont) + 1);
- delPCont[High(delPCont)] := contact.LUID;
- end;
- end;
- Node := ListContacts.GetNext(Node);
- end;
-
- ListContacts.BeginUpdate;
- try
- // first apply phone changes
- for j := 0 to pl.Count-1 do begin
- F := '';
-
- if Pos('M:', pl[j]) = 1 then begin //entries modified
- LUID := Copy(pl[j], Pos('::', pl[j]) + 2, length(pl[j]));
- if LFindContact(LUID,contact) then begin
- F := GetContactFullName(contact);
- migrate := contact^;
- AsNew := False;
- end
- else
- AsNew := True;
- if CheckInArray(addPCont, LUID) then begin
- PhoneOnPC := PromptConflict(F, 'is modified on phone and modified on pc.');
- if not PhoneOnPC then continue; // later will overwrite phone contact
- // else overwrite local contact
- end;
- if CheckInArray(delPCont, LUID) then begin
- PhoneOnPC := PromptConflict(F, 'is modified on phone and deleted on pc.');
- if not PhoneOnPC then continue; // later will delete phone contact
- // else resurrect local contact
- end;
- //Get new VCard
- Form1.ObexGetObject('telecom/pb/luid/' + LUID + '.vcf',sl);
- VCard.Clear;
- VCard.Raw := sl;
- //Remove old VCard
- if not AsNew then
- EraseContact(LUID,False);
- //Add new Node and Parse VCard
- Node := ListContacts.AddChild(nil);
- contact := ListContacts.GetNodeData(Node);
- vCard2Contact(VCard,contact);
- contact.stateindex := 3;
- //Migrate Fma internal settings
- if not AsNew then
- MigrateContact(@migrate,contact);
- // TODO: add picture and sound support here....
- if AsNew then
- SyncLog(GetvCardFullName(VCard) + ' added to FMA by phone.')
- else
- SyncLog(GetvCardFullName(VCard) + ' modified in FMA by phone.');
- VCard.Clear;
- sl.Clear;
- // Update LOG Number dinamicaly (current LOG record has been processed)
- CC := Copy(pl[j],3,Pos('::',pl[j])-3);
- Result := True;
- end;
-
- if Pos('H:', pl[j]) = 1 then begin //entries deleted
- LUID := Copy(pl[j], Pos('::', pl[j]) + 2, length(pl[j]));
- if LFindContact(LUID,contact) then begin
- F := GetContactFullName(contact);
- AsNew := False;
- end
- else
- AsNew := True;
- if CheckInArray(addPCont, LUID) then begin
- PhoneOnPC := PromptConflict(F, 'is deleted on phone and modified on pc.');
- if not PhoneOnPC then continue; // later will resurrect phone contact
- // else delete local contact
- end;
- EraseContact(LUID,False);
- if CheckInArray(delPCont, LUID) then
- SyncLog(F + ' deleted in phone by FMA.')
- else if not AsNew then
- SyncLog(F + ' deleted in FMA by phone.');
- // Update LOG Number dinamicaly (current LOG record has been processed)
- CC := Copy(pl[j],3,Pos('::',pl[j])-3);
- Result := True;
- end;
- end;
- { well, we have processed all "CC.log" entries and we have updated CC up to latest one }
- SetLength(addPCont,0);
- SetLength(delPCont,0);
-
- // Build lists of contacts modified and deleted in phone
- for j := 0 to pl.Count-1 do begin
- if Pos('M:', pl[j]) = 1 then begin //entries modified
- SetLength(addPCont, length(addPCont) + 1);
- addPCont[High(addPCont)] := Copy(pl[j], Pos('::', pl[j]) + 2, length(pl[j]));
- end
- else if Pos('H:', pl[j]) = 1 then begin //entries deleted
- SetLength(delPCont, length(delPCont) + 1);
- delPCont[High(delPCont)] := Copy(pl[j], Pos('::', pl[j]) + 2, length(pl[j]));
- end;
- end;
-
- // next apply PC changes
- try
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- contact := ListContacts.GetNodeData(node);
- if contact.StateIndex <> 3 then begin // skip unmodified contacts
- Contact2vCard(contact,VCard);
- // TODO: add picture and sound support here....
- stream := TMemoryStream.Create;
- try
- VCard.Raw.SaveToStream(stream);
- VCard.Clear;
- stream.Seek(0, soFromBeginning);
- F := GetContactFullName(contact);
- case contact.StateIndex of
- 0: begin //new
- //TODO: check if contact with same name already exists
- contact.LUID := Form1.ObexPutObject('telecom/pb/luid/.vcf', stream); //New LUID
- contact.StateIndex := 3; //entries syncronized
- SyncLog(F + ' added to phone by FMA.');
- Result := True;
- end;
- 1: begin //modified
- AsNew := CheckInArray(delPCont, contact.LUID);
- if AsNew then begin
- contact.LUID := Form1.ObexPutObject('telecom/pb/luid/.vcf', stream); //New LUID
- SyncLog(F + ' added to phone by FMA.');
- end
- else begin
- contact.LUID := Form1.ObexPutObject('telecom/pb/luid/' + contact.luid + '.vcf', stream); //Modified LUID
- SyncLog(F + ' modified in phone by FMA.');
- end;
- contact.StateIndex := 3; //entries syncronized
- Result := True;
- end;
- 2: begin //deleted
- contact.LUID := Form1.ObexPutObject('telecom/pb/luid/' + contact.luid + '.vcf', nil); //deletd LUID
- contact.StateIndex := 3; //entries syncronized
- ListContacts.DeleteNode(Node);
- SyncLog(F + ' deleted in phone by FMA.');
- Result := True;
- end;
- end;
- finally
- stream.Free;
- end;
- end;
- Node := ListContacts.GetNext(Node);
- end;
- finally
- // get current LOG Number from phone -- it will include all changes made in FMA that we just apply to phone
- Form1.ObexGetObject('telecom/pb/luid/cc.log',sl);
- CC := sl.Strings[0];
- end;
- finally
- RenderGUIDs;
- ListContacts.EndUpdate;
- end;
-
- {
- SN:351956003653753
- DID:6D25
- Total-Records:100
- Maximum-Records:510
- *
- }
- // Do we have to perform a full refresh? (too many changes in phone)
- // Local changes have been applied to the phone already, so we can do
- // full refresh, if needed...
- if pl[pl.Count-1] = '*' then begin
- Result := FullRefresh;
- exit;
- end;
- finally
- sl.Free;
- pl.Free;
- Form1.ObexDisconnect;
- ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection);
- ListContacts.Update;
- UndoLastChange1.Enabled := False;
- end;
- Result := Result or UpdatePositions;
- end;
-
- {Utilities}
-
- function TfrmSyncPhonebook.CheckInArray(A: array of widestring;
- S: Widestring): boolean;
- var
- i:Integer;
- begin
- for i:=0 to High(A) do begin
- if A[i] = S then begin
- Result := True;
- Exit;
- end;
- end;
- Result := False;
- end;
-
- {
- procedure TfrmSyncPhonebook.ResetInArray(var A: array of widestring;
- S: Widestring);
- var
- i:Integer;
- begin
- for i:=0 to High(A) do begin
- if A[i] = S then begin
- A[i] := '';
- end;
- end;
- end;
- }
-
- function TfrmSyncPhonebook.EraseContact(LUID :Widestring; Log:Boolean):Boolean;
- var
- Node: PVirtualNode;
- contact: PContactData;
- begin
- Result := False;
- with ListContacts do begin
- Node := GetFirst;
- while Node <> nil do begin
- contact := GetNodeData(node);
- if LUID = contact.LUID then begin
- if Log then
- SyncLog(GetContactFullName(contact) + ' deleted in FMA by phone.');
- DeleteNode(Node);
- Result := True;
- break;
- end;
- Node := GetNext(Node);
- end;
- end;
- end;
-
- function TfrmSyncPhonebook.PromptConflict(NameContact: WideString; Info:WideString): boolean;
- begin
- frmPromptConflict := TfrmPromptConflict.Create(Self);
- Result := true;
- With frmPromptConflict do begin
- lblContact.Caption := NameContact;
- lblInfo.Caption := Info;
- if ShowModal = mrOK then begin
- if grpConflict.ItemIndex = 0 then
- Result := True
- else
- Result := False;
- end;
- end;
-
- frmPromptConflict.Free;
- end;
-
- procedure TfrmSyncPhonebook.SyncLog(Desc: WideString);
- begin
- Form1.SyncLog(Desc);
- end;
-
- procedure TfrmSyncPhonebook.btnLOGClick(Sender: TObject);
- begin
- GetSyncLogWindow.Show;
- end;
-
- procedure TfrmSyncPhonebook.ForceUpdateClick(Sender: TObject);
- begin
- ForceContact(1);
- end;
-
- procedure TfrmSyncPhonebook.ExportList(FileType:Integer; Filename: WideString);
- var
- node: PVirtualNode;
- contact: PContactData;
- sl: TStringList;
- str: WideString;
- XML: TXML;
- begin
- case FileType of
- 1:begin//vCard
- sl := TStringList.Create;
- with ListContacts do begin
- node := GetFirst;
- repeat
- try
- if Selected[node] then begin
- contact := GetNodeData(node);
- Contact2vCard(contact,VCard);
- //TODO: add picture and sound support here....
- sl.Clear;
- sl.AddSTrings(VCard.Raw);
- if ListContacts.SelectedCount <> 1 then begin
- str := Trim(GetContactFullName(contact));
- str := StringReplace(str,' ','-',[rfReplaceAll]);
- str := ChangeFileExt(FileName,'-'+str)+ExtractFileExt(Filename);
- sl.SaveToFile(str);
- end
- else
- sl.SaveToFile(Filename);
- end;
- except
- end;
- node := GetNext(node);
- until node = nil;
- end;
- sl.Free;
- end;
- 2:begin//CSV
- sl := TStringList.Create;
- str := '"Title","First Name","Last Name","Company","E-mail Address","E-mail Display Name","Home Phone","Business Phone",'+
- '"Mobile Phone","Business Fax","Other Phone","Primary Phone"';
- sl.add(str);
- with ListContacts do begin
- node := GetFirst;
- repeat
- try
- if Selected[node] then begin
- { Bug 847307 Export to .csv files.
- Fixed to use "," instead of ";" and field names compatability with Outlook 2003 fields, which are shown here:
- "Title","First Name","Middle Name","Last Name","Suffix","Company","Department","Job Title","Business Street",
- "Business Street 2","Business Street 3","Business City","Business State","Business Postal Code","Business Country",
- "Home Street","Home Street 2","Home Street 3","Home City","Home State","Home Postal Code","Home Country",
- "Other Street","Other Street 2","Other Street 3","Other City","Other State","Other Postal Code","Other Country",
- "Assistant's Phone","Business Fax","Business Phone","Business Phone 2","Callback","Car Phone","Company Main Phone",
- "Home Fax","Home Phone","Home Phone 2","ISDN","Mobile Phone","Other Fax","Other Phone","Pager","Primary Phone",
- "Radio Phone","TTY/TDD Phone","Telex","Account","Anniversary","Assistant's Name","Billing Information","Birthday",
- "Business Address PO Box","Categories","Children","Directory Server","E-mail Address","E-mail Type","E-mail Display Name",
- "E-mail 2 Address","E-mail 2 Type","E-mail 2 Display Name","E-mail 3 Address","E-mail 3 Type","E-mail 3 Display Name",
- "Gender","Government ID Number","Hobby","Home Address PO Box","Initials","Internet Free Busy","Keywords","Language",
- "Location","Manager's Name","Mileage","Notes","Office Location","Organizational ID Number","Other Address PO Box",
- "Priority","Private","Profession","Referred By","Sensitivity","Spouse","User 1","User 2","User 3","User 4","Web Page" }
- contact := GetNodeData(node);
- str := WideQuoteStr(contact.title) + ',' +
- WideQuoteStr(contact.name) + ',' +
- WideQuoteStr(contact.surname) + ',' +
- WideQuoteStr(contact.org) + ',' +
- WideQuoteStr(contact.email) + ',' +
- WideQuoteStr(contact.displayname) + ',' +
- WideQuoteStr(contact.home) + ',' +
- WideQuoteStr(contact.work) + ',' +
- WideQuoteStr(contact.cell) + ',' +
- WideQuoteStr(contact.fax) + ',' +
- WideQuoteStr(contact.other) + ',' +
- WideQuoteStr(GetContactDefPhone(contact));
- sl.add(str);
- end;
- except
- end;
- node := GetNext(node);
- until node = nil;
- end;
- sl.SaveToFile(FileName);
- sl.Free;
- end;
- 3:begin//XML
- XML := TXML.Create();
- try
- XML.TagName := 'fma_contacts';
-
- with ListContacts do
- begin
- Node := GetFirst();
-
- while assigned(Node) do
- begin
- if Selected[Node] then
- with XML.AddChild('contact') do
- begin
- Contact := GetNodeData(Node);
-
- AddChild('title', HTMLEncode(UTF8Encode(contact.title), False));
- AddChild('name', HTMLEncode(UTF8Encode(contact.name), False));
- AddChild('surname', HTMLEncode(UTF8Encode(contact.surname), False));
- AddChild('org', HTMLEncode(UTF8Encode(contact.org), False));
- AddChild('email', HTMLEncode(UTF8Encode(contact.email), False));
- AddChild('home', HTMLEncode(UTF8Encode(contact.home), False));
- AddChild('work', HTMLEncode(UTF8Encode(contact.work), False));
- AddChild('cell', HTMLEncode(UTF8Encode(contact.cell), False));
- AddChild('fax', HTMLEncode(UTF8Encode(contact.fax), False));
- AddChild('other', HTMLEncode(UTF8Encode(contact.other), False));
- end;
-
- Node := GetNext(Node);
- end;
- end;
-
- XML.Save(FileName);
-
- finally
- XML.Free();
- end;
-
- end;
- 4:begin//HTML
- sl := TStringList.Create;
- sl.Add('<html><head><meta content="text/html;charset=utf-8" http-equiv="content-type">');
- sl.Add('<title>FMA Contacts</title></head><body>');
- sl.Add('<TABLE BORDER="1">');
- sl.Add('<TR><TD>Title</TD><TD>Name</TD><TD>Surname</TD><TD>Organization</TD><TD>Email</TD>');
- sl.Add('<TD>Home</TD><TD>Work</TD><TD>Cell</TD><TD>Fax</TD><TD>Other</TD></TR>');
- with ListContacts do begin
- node := GetFirst;
- repeat
- try
- if Selected[node] then begin
- contact := GetNodeData(node);
- str := '<TR>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.title),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.name),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.surname),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.org),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.email),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.home),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.work),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.cell),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.fax),False) + '</TD>';
- str := str + '<TD>' + HTMLEncode(UTF8Encode(contact.other),False) + '</TD>';
- str := str + '</TR>';
- sl.add(str);
- end;
- except
- end;
- node := GetNext(node);
- until node = nil;
- end;
- sl.Add('</TABLE>');
- sl.Add('</body></html>');
- sl.SaveToFile(FileName);
- sl.Free;
- end;
- end;
- end;
-
- procedure TfrmSyncPhonebook.ForceNewContactClick(Sender: TObject);
- begin
- ForceContact(0);
- end;
-
- procedure TfrmSyncPhonebook.ForceContact(State: integer);
- var
- node: PVirtualNode;
- contact: PContactData;
- begin
- with ListContacts do
- try
- BeginUpdate;
- node := GetFirst;
- repeat
- try
- if Selected[node] then begin
- contact := GetNodeData(node);
- if contact.StateIndex <> 0 then contact.StateIndex := State;
- end;
- except
- end;
- node := GetNext(node);
- until node = nil;
- finally
- EndUpdate;
- end;
- end;
-
- procedure TfrmSyncPhonebook.ListContactsAfterPaint(
- Sender: TBaseVirtualTree; TargetCanvas: TCanvas);
- begin
- NoItemsPanel.Visible := ListContacts.ChildCount[nil] = 0;
- end;
-
- procedure TfrmSyncPhonebook.PopupMenu1Popup(Sender: TObject);
- var
- i: integer;
- m: TMenuItem;
- contact: PContactData;
- begin
- DownloadEntirePhonebook1.Enabled := Form1.FConnected and not Form1.FObex.Connected;
- Properties1.Enabled := ListContacts.SelectedCount = 1;
- AddtoGroup1.Clear;
- if Assigned(Form1.FNodeGroups) then begin
- for i := 0 to Form1.FNodeGroups.Count-1 do begin
- m := TMenuItem.Create(nil);
- try
- m.AutoHotkeys := maManual;
- m.Caption := Form1.FNodeGroups.Item[i].Text;
- m.Tag := Form1.FNodeGroups.Item[i].StateIndex;
- m.ImageIndex := 53;
- m.OnClick := AddToGroupClick;
- AddtoGroup1.Add(m);
- except
- m.Free;
- end;
- end;
- end;
- if Properties1.Enabled then begin
- contact := ListContacts.GetNodeData(ListContacts.FocusedNode);
- AddtoGroup1.Enabled := (AddtoGroup1.Count <> 0) and // do we have groups at all?
- (contact.StateIndex in [1,3]); // work only for modified and normal contacts, exclude new and deleted ones
- end
- else
- AddtoGroup1.Enabled := False;
- end;
-
- procedure TfrmSyncPhonebook.AddToGroupClick(Sender: TObject);
- var
- Node: PVirtualNode;
- Person: PContactData;
- i,index: integer;
- cname,cnumb: WideString;
- dlg: TfrmStatusDlg;
- begin
- dlg := ShowStatusDlg('Adding to Group...');
- with dlg do
- try
- Node := ListContacts.GetFirst;
- while Node <> nil do
- try
- if ListContacts.Selected[Node] then begin
- Person := ListContacts.GetNodeData(Node);
- cname := GetContactFullName(Person);
- with TfrmAddToGroup.Create(nil) do
- try
- Contact := Person;
- lblGroup.Caption := (Sender as TMenuItem).Caption;
- if (clNumbers.Count = 1) or (ShowModal = mrOk) then begin
- { Default number }
- if RadioButton1.Checked then begin
- index := ContactDefPosition(Person);
- if index < 1 then
- index := Form1.LocatePBIndex('ME',cname,GetContactDefPhone(Person));
- if index > 0 then begin
- { Remember found position, ie. make a cache here }
- ContactDefPosition(Person,index);
- { Add to group }
- Form1.Status('Adding to group...');
- with (Sender as TMenuItem) do begin
- Form1.TxAndWait('AT*ESAG='+IntToStr(Tag)+',2,'+IntToStr(index));
- // TODO: Do not add dublicates to groups
- //Form1.ExplorerAddToGroup(Tag,cname);
- end;
- end;
- end
- else begin
- { Custom numbers }
- for i := 0 to clNumbers.Count-1 do
- if clNumbers.Checked[i] then begin
- cnumb := GetNumber(i);
- index := GetContactPosition(Person,cnumb);
- if index < 1 then
- index := Form1.LocatePBIndex('ME',cname,cnumb);
- if index > 0 then begin
- { Remember found position, ie. make a cache here }
- SetContactPosition(Person,cnumb,index);
- { Add to group }
- Form1.Status('Adding to group...');
- with (Sender as TMenuItem) do begin
- Form1.TxAndWait('AT*ESAG='+IntToStr(Tag)+',2,'+IntToStr(index));
- //Form1.ExplorerAddToGroup(Tag,cname);
- end;
- end;
- end;
- end;
- end
- else
- dlg.Close;
- finally
- Free;
- end;
- end;
- finally
- Node := ListContacts.GetNext(Node);
- end;
- Form1.InitGroups;
- Form1.SaveData;
- finally
- Free;
- end;
- end;
-
- function TfrmSyncPhonebook.UpdatePositions: boolean;
- var
- contact: PContactData;
- // Node :PVirtualNode;
- // NeedUpdate: Boolean;
- sl: TStringList;
- function SameContact(Name,Number: WideString): boolean;
- var
- s: string;
- begin
- s := contact.name;
- if contact.surname <> '' then s := s + ' ' + contact.surname;
- Result := (s = Name) and
- ((contact.home = Number) or
- (contact.work = Number) or
- (contact.cell = Number) or
- (contact.fax = Number) or
- (contact.other = Number)
- );
- end;
- function FindNumber: integer;
- var
- i,position: integer;
- slTmp: TStringList;
- Name, Number: String;
- begin
- Result := 0;
- slTmp := TStringList.Create;
- try
- for i := 0 to sl.Count-1 do
- if pos('+CPBR', sl[i]) = 1 then begin
- slTmp.DelimitedText := sl[i];
-
- position := StrToInt(slTmp.Strings[1]);
- Number := slTmp.Strings[2];
- if Form1.FUseUTF8 then
- Name := UTF8Decode(slTmp.Strings[4])
- else
- Name := slTmp.Strings[4];
- if (Length(Name) > 2) and (Name[Length(Name)-1] = '/') then
- SetLength(Name,Length(Name)-2);
-
- if (slTmp.Strings[3] = '145') and (Number[1] <> '+') then
- Number := '+' + Number;
-
- if SameContact(Name,Number) then begin
- Result := position;
- Form1.Debug(Name+' '+Number+' @ '+IntToStr(position));
- break;
- end;
- end;
- finally
- slTmp.Free;
- end;
- end;
- begin
- Result := False;
- // temporary exit, since we are using another method to retrieve PB position.
- exit;
- {
- if Form1.FConnected then begin
- if (cardinal(Form1.FNodeContactsME.Count) = ListContacts.ChildCount[nil]) then begin
- NeedUpdate := False;
- Node := ListContacts.GetFirst;
- while Node <> nil do
- try
- contact := ListContacts.GetNodeData(Node);
- if NumPosEmpty(contact) then begin // if some item doesn't have position yet?
- NeedUpdate := true;
- break;
- end;
- finally
- Node := ListContacts.GetNext(Node);
- end;
- end
- else begin
- NeedUpdate := True;
- Result := True; // we'll add/remove items, so always report 'change'
- end;
- if NeedUpdate then begin
- sl := TStringList.Create;
- try
- Form1.GetPhonebook('ME',sl);
- // TODO: da se slohi cikyl po sl, a gore po ListContacts
- Node := ListContacts.GetFirst;
- while Node <> nil do
- try
- contact := ListContacts.GetNodeData(Node);
- if NumPosEmpty(contact) then begin
- // TODO: Add phone type, not only cell
- contact.Position.cell := FindNumber;
- Result := True;
- end;
- finally
- Node := ListContacts.GetNext(Node);
- end;
- finally
- sl.Free;
- end;
- end;
- end;
- }
- end;
-
- function TfrmSyncPhonebook.DoEdit(AsNew: boolean; NewNumber: string; ContactData: PContactData): boolean;
- var
- Node: PVirtualNode;
- procedure SyncChanges;
- begin
- ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection);
- ListContacts.Update;
- Form1.UpdateMEPhonebook;
- { Focus moved edited item in the list }
- if ListContacts.FocusedNode <> nil then begin
- Node := ListContacts.FocusedNode;
- ListContacts.FocusedNode := nil;
- ListContacts.FocusedNode := Node;
- end;
- end;
- begin
- Result := False;
- if ContactData <> nil then begin
- SelContact := ContactData;
- AsNew := False;
- end;
- if AsNew then State := 0
- else begin
- State := Selcontact.StateIndex;
- if State = 0 then State := 4 //new >> modified
- else if State = 3 then State := 1;
- end;
- with TfrmEditContact.Create(nil) do
- try
- IsNew := (State = 0) or (Selcontact = nil);
- // set restrictions
- MaxFullNameLen := FMaxNameLen;
- txtName.MaxLength := FMaxNameLen;
- txtDisplayAs.MaxLength := FMaxNameLen; //??
- txtTitle.MaxLength := FMaxTitleLen;
- txtOrganization.MaxLength := FMaxOrgLen;
- txtEmail.MaxLength := FMaxMailLen;
- txtHome.MaxLength := FMaxTellen;
- txtWork.MaxLength := FMaxTellen;
- txtCell.MaxLength := FMaxTellen;
- txtFax.MaxLength := FMaxTellen;
- txtOther.MaxLength := FMaxTellen;
- // update contact state
- if IsNew then begin
- FillChar(contact,SizeOf(contact),0);
- contact.cell := NewNumber;
- end
- else
- contact := Selcontact^;
- // record undo info, or set own card mode
- if ContactData = nil then FUndoEdit := contact
- else UseOwnMode := True;
- // edit contact
- if ShowModal = mrOk then begin
- if Modified then with ListContacts do begin
- // apply total updates
- BeginUpdate;
- try
- if IsNew then begin // create new node
- FocusedNode := AddChild(nil);
- Selcontact := ListContacts.GetNodeData(FocusedNode);
- end;
- { copy all data }
- Selcontact^ := contact;
- if IsNew then begin // new node, update IDs
- Selcontact^.LUID := '';
- Selcontact^.CDID := NewGUID;
- end;
- Selcontact^.stateindex := State;
- if State = 4 then Selcontact^.stateindex := 0;
- if (State > 0) and (ContactData = nil) then
- UndoLastChange1.Enabled := True; // undo not works on new contact
- Result := True;
- finally
- RenderGUIDs;
- EndUpdate;
- SyncChanges;
- end;
- end else
- if customModified then with ListContacts do begin
- // apply only Fma custom data updates
- BeginUpdate;
- try
- { copy custom data only }
- Selcontact^.displayname := contact.displayname;
- Selcontact^.DefaultIndex := contact.DefaultIndex;
- Selcontact^.Position := contact.Position;
- Selcontact^.picture := contact.picture;
- Selcontact^.sound := contact.sound;
- SelContact^.CDID := contact.CDID;
- if ContactData = nil then UndoLastChange1.Enabled := True;
- Result := True;
- finally
- EndUpdate;
- SyncChanges;
- end;
- end;
- end;
- finally
- Free;
- end;
- end;
-
- procedure TfrmSyncPhonebook.UndoLastChange1Click(Sender: TObject);
- var
- Node :PVirtualNode;
- begin
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- if Node.Index = FUndoIndx then break;
- Node := ListContacts.GetNext(Node);
- end;
- if Node <> nil then begin
- { multiselect is enabled, so this is not correct
- if ListContacts.FocusedNode <> nil then
- ListContacts.FocusedNode.States := ListContacts.FocusedNode.States - [vsSelected];
- Node.States := Node.States + [vsSelected];
- }
- ListContacts.FocusedNode := Node;
- ListContacts.ScrollIntoView(Node,True);
- Selcontact := ListContacts.GetNodeData(Node);
- SelContact^ := FUndoEdit;
- UndoLastChange1.Enabled := False;
- ListContacts.Repaint;
- { refresh explorer view on-the-fly (it's quick, don't worry) }
- Form1.UpdateMEPhonebook;
- end;
- end;
-
- procedure TfrmSyncPhonebook.ListContactsIncrementalSearch(
- Sender: TBaseVirtualTree; Node: PVirtualNode;
- const SearchText: WideString; var Result: Integer);
- var
- Contact: PContactData;
- Text: WideString;
- begin
- Contact := ListContacts.GetNodeData(Node);
- Text := Copy(GetContactDisplayName(Contact),1,Length(SearchText));
- Result := WideCompareText(SearchText,Text);
- end;
-
- procedure TfrmSyncPhonebook.ListContactsKeyDown(Sender: TObject;
- var Key: Word; Shift: TShiftState);
- begin
- if (Key = VK_RETURN) and (ListContacts.SelectedCount = 1) then
- btnEditClick(nil);
- end;
-
- procedure TfrmSyncPhonebook.ImportContacts1Click(Sender: TObject);
- var
- i,adds,mods: integer;
- Node,ANode: PVirtualNode;
- contact: PContactData;
- sl: TStringList;
- F: WideString;
- Modified: boolean;
- dlg: TfrmConnect;
- begin
- if not OpenDialog1.Execute then exit;
- Update;
- dlg := GetProgressDialog;
- try
- if Form1.CanShowProgress then
- dlg.ShowProgress(Form1.FProgressLongOnly);
- dlg.Initialize(OpenDialog1.Files.Count,'Importing phonebook contacts');
-
- Form1.Status('Importing contacts...');
- SyncLog('Import started');
-
- adds := 0; mods := 0;
- //ListContacts.BeginUpdate;
- sl := TStringList.Create;
- try
- for i := 0 to OpenDialog1.Files.Count-1 do begin
- sl.LoadFromFile(OpenDialog1.Files[i]);
- dlg.IncProgress(1);
- VCard.Clear;
- VCard.Raw := sl;
- F := GetvCardFullName(VCard);
- Modified := False;
- //erase the old entry if present
- if FindContact(F,ANode) then begin
- contact := ListContacts.GetNodeData(ANode);
- case MessageDlg(F + ' [' + GetContactDefPhone(contact) +
- '] already exists. Do you want to replace it now?'#13#13'(Click No to add it as a New contact)',
- mtConfirmation,[mbYes,mbNo,mbCancel],0) Of
- mrYes: begin
- ListContacts.DeleteNode(ANode);
- SyncLog(F + ' modified in FMA by Import.');
- Modified := True;
- end;
- mrNo: SyncLog(F + ' added to FMA by Import (as dublicate).');
- mrCancel: Abort;
- end;
- end
- else SyncLog(F + ' added to FMA by Import.');
- Node := ListContacts.AddChild(nil);
- contact := ListContacts.GetNodeData(Node);
- vCard2Contact(VCard,contact);
- if Modified then begin
- contact.stateindex := 1;
- inc(mods);
- end
- else begin
- contact.stateindex := 0;
- inc(adds);
- end;
- // TODO: add picture and sound support here....
- ListContacts.Update;
- end;
- finally
- sl.free;
- if (adds <> 0) or (mods <> 0) then begin
- RenderGUIDs;
- //ListContacts.EndUpdate;
- ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection);
- ListContacts.Update;
- Form1.UpdateMEPhonebook;
- Form1.Debug('Imported '+IntToStr(adds+mods)+' item(s)... ('+IntToStr(adds)+' added, '+IntToStr(mods)+' modified)');
- end;
- end;
- finally
- FreeProgressDialog;
- SyncLog('Import finished');
- Form1.Status('Import complete.');
- end;
- end;
-
- function TfrmSyncPhonebook.FindContact(FullName: WideString;
- var AContact: PContactData): boolean;
- var
- Node :PVirtualNode;
- begin
- Result := False;
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- AContact := ListContacts.GetNodeData(Node);
- if WideCompareText(FullName,GetContactFullName(AContact)) = 0 then begin
- Result := True;
- break;
- end;
- Node := ListContacts.GetNext(Node);
- end;
- end;
-
- function TfrmSyncPhonebook.FindContact(FullName: WideString;
- var ANode: PVirtualNode): boolean;
- var
- AContact: PContactData;
- begin
- Result := False;
- ANode := ListContacts.GetFirst;
- while ANode <> nil do begin
- AContact := ListContacts.GetNodeData(ANode);
- if WideCompareText(FullName,GetContactFullName(AContact)) = 0 then begin
- Result := True;
- break;
- end;
- ANode := ListContacts.GetNext(ANode);
- end;
- end;
-
- procedure TfrmSyncPhonebook.ClearChangedFlag1Click(Sender: TObject);
- begin
- ForceContact(3);
- end;
-
- function TfrmSyncPhonebook.GetPhoneCapacity: Integer;
- var
- i: Integer;
- buffer, stop: String;
- slTmp: TStrings;
- begin
- Form1.TxAndWait('AT+CPBS="ME"');
- Form1.TxAndWait('AT+CPBR=?');
- // defaults
- buffer := '';
- stop := '510'; FMaxNameLen := 180; FMaxTelLen := 80;
- // +CPBR: (1-200),80,180
- for i := 0 to Form1.FRxBuffer.Count-1 do
- if Pos('+CPBR',Form1.FRxBuffer.Strings[i]) = 1 then begin
- buffer := Form1.FRxBuffer.Strings[i];
- break;
- end;
- for i := 1 to length(buffer) do begin
- if IsDelimiter('()-,', buffer, i) then buffer[i] := ' ';
- end;
- // +CPBR: 1 200 80 180
- if buffer <> '' then begin
- slTmp := TStringList.Create;
- try
- slTmp.DelimitedText := buffer;
- stop := slTmp.Strings[2];
- Form1.Debug('Phonebook: max entries = '+stop);
- FMaxTelLen := StrToInt(slTmp.Strings[3]);
- Form1.Debug('Phonebook: max tel length = '+slTmp.Strings[3]);
- FMaxNameLen := StrToInt(slTmp.Strings[4]);
- Form1.Debug('Phonebook: max name length = '+slTmp.Strings[4]);
- finally
- slTmp.Free;
- end;
- end;
- Result := StrToInt(stop);
- end;
-
- procedure TfrmSyncPhonebook.OnConnected;
- begin
- FMaxRecME := GetPhoneCapacity;
- end;
-
- procedure TfrmSyncPhonebook.RenderGUIDs;
- var
- contact: PContactData;
- Node: PVirtualNode;
- begin
- { Make sure all contacts' GUIDs are unique }
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- contact := ListContacts.GetNodeData(Node);
- repeat
- if IsUniqueGUID(contact) then break;
- contact.CDID := NewGUID;
- until False;
- Node := ListContacts.GetNext(Node);
- end;
- end;
-
- function TfrmSyncPhonebook.IsUniqueGUID(who: PContactData): boolean;
- var
- Node: PVirtualNode;
- contact: PContactData;
- begin
- { Checks whether who contact has an unique GUID field }
- Result := True;
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- contact := ListContacts.GetNodeData(Node);
- if (contact <> who) and (GUIDToString(contact.CDID) = GUIDToString(who.CDID)) then begin
- Result := False;
- break;
- end;
- Node := ListContacts.GetNext(Node);
- end;
- end;
-
- function TfrmSyncPhonebook.FullRefresh: boolean;
- var
- sl : TStringList;
- cardstr : TStringList;
- //ListCont :TStringList;
- //str : String;
- slCC :TStringList;
- i:Integer;
- AsNew,isAgent,isBody: Boolean;
- migrate: TContactData;
- contact: PContactData;
- Node,TmpNode: PVirtualNode;
- begin
- Result := False;
- //check if start OBEX
- if not Form1.FConnected then begin
- ShowMessage('The Sync Phonebook can''t start...try to restart your phone.');
- SyncLog('The Sync Phonebook can''t start...try to restart your phone.');
- btnSync.Enabled := True;
- Form1.ActionSyncPhonebook.Enabled := True;
- exit;
- end;
- Update;
- sl := TStringList.Create;
- cardstr := TStringList.Create;
- //ListCont := TStringList.Create;
- //Start get of entire phonebook
- Form1.ObexConnect('IRMC-SYNC'); //start sync process
- try
- Form1.ObexGetObject('telecom/pb.vcf',sl,True,'entire phonebook');
- slCC := TStringList.Create;
- try
- Form1.ObexGetObject('telecom/pb/luid/cc.log',slCC); //Take CC
- CC := slCC.Strings[0];
- finally
- slCC.Free;
- end;
- finally
- Form1.ObexDisconnect; //close the connection
- end;
-
- ListContacts.BeginUpdate;
- try
- { Mark all entries as deleted }
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- contact := ListContacts.GetNodeData(Node);
- contact.StateIndex := 2;
- Node := ListContacts.GetNext(Node);
- end;
- try
- { Process phonebook entries }
- isBody := False;
- VCard.clear;
- isAgent := False;
- for i := 0 to sl.Count - 1 do begin
- { check for nested vCard and ignore it, if any }
- if pos('AGENT', sl.Strings[i]) = 1 then isAgent := True;
- if isAgent then begin
- if pos('END', sl.Strings[i]) = 1 then isAgent := False;
- Continue;
- end;
- { process vCard data }
- if pos('BEGIN', sl.Strings[i]) = 1 then isBody := True;
- if isBody then begin
- cardstr.add(sl.Strings[i]);
- end;
- if pos('END', sl.Strings[i]) = 1 then begin
- isBody := False;
- VCard.Raw := cardstr;
- cardstr.Clear;
- if LFindContact(VCard.LUID,contact) then begin
- migrate := contact^;
- AsNew := False;
- end
- else
- AsNew := True;
- if not AsNew then
- EraseContact(VCard.LUID,False);
- //Add new Node and Parse VCard
- Node := ListContacts.AddChild(nil);
- contact := ListContacts.GetNodeData(Node);
- vCard2Contact(VCard,contact);
- contact.stateindex := 3;
- //Migrate Fma internal settings
- if not AsNew then
- MigrateContact(@migrate,contact);
- // TODO: add picture and sound support here....
- SyncLog(GetvCardFullName(VCard) + ' added to FMA by phone.');
- VCard.Clear;
- end;
- end;
- finally
- { Clear all deleted entries }
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- contact := ListContacts.GetNodeData(Node);
- if contact.StateIndex <> 3 then begin
- TmpNode := Node;
- Node := ListContacts.GetNext(Node);
- ListContacts.DeleteNode(TmpNode);
- SyncLog(GetContactFullName(contact) + ' is obsolete in FMA.');
- end
- else
- Node := ListContacts.GetNext(Node);
- end;
- end;
- UpdatePositions;
- DoFirstImportCheck;
- Result := True;
- finally
- ListContacts.EndUpdate;
- ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection);
- ListContacts.Update;
- UndoLastChange1.Enabled := False;
- sl.Free;
- cardstr.Free;
- //listcont.Free;
- end;
- end;
-
- function TfrmSyncPhonebook.LFindContact(LUID: Widestring;
- var AContact: PContactData): Boolean;
- var
- Node: PVirtualNode;
- contact: PContactData;
- begin
- Result := False;
- with ListContacts do begin
- Node := GetFirst;
- while Node <> nil do begin
- contact := GetNodeData(node);
- if LUID = contact.LUID then begin
- AContact := contact;
- Result := True;
- break;
- end;
- Node := GetNext(Node);
- end;
- end;
- end;
-
- procedure TfrmSyncPhonebook.DoFirstImportCheck;
- var
- Node: PVirtualNode;
- contact: PContactData;
- HasCells,HasHomes: boolean;
- s: string;
- begin
- HasCells := False;
- HasHomes := False;
- with ListContacts do begin
- Node := GetFirst;
- while Node <> nil do begin
- contact := GetNodeData(node);
- if contact.cell <> '' then HasCells := True;
- if contact.home <> '' then HasHomes := True;
- Node := GetNext(Node);
- end;
- end;
- { Is this first import from 'old' phone which keep numbers into Home position
- instead of Cell one? This usualy happens when one imports all contacts
- from its SIM card into Phone's memory (phonebook). }
- if not HasCells and HasHomes then
- { Yes, offer exchange }
- if MessageDlg('It seams that all your phone numbers are stored into Home positions. '+
- 'Do you wish to exchange them with Cell ones?',mtConfirmation,[mbYes,mbNo],0) = ID_YES then begin
- with ListContacts do begin
- Node := GetFirst;
- while Node <> nil do begin
- contact := GetNodeData(node);
- if contact.home <> '' then begin
- s := contact.cell;
- contact.cell := contact.home;
- contact.home := s;
- contact.StateIndex := 1; // modified
- end;
- Node := GetNext(Node);
- end;
- end;
- end;
- end;
-
- procedure TfrmSyncPhonebook.FirstLast1Click(Sender: TObject);
- begin
- (Sender as TMenuItem).Checked := True;
- ListContacts.Sort(nil, ListContacts.Header.SortColumn, ListContacts.Header.SortDirection);
- end;
-
- procedure TfrmSyncPhonebook.DownloadEntirePhonebook1Click(Sender: TObject);
- begin
- if MessageDlg('Local Phonebook will be replaced with a fresh copy from the phone.'#13#13+
- 'Any local changes will be lost. Do you wish to continue?',
- mtConfirmation,[mbYes,mbNo],0) = ID_YES then begin
- ListContacts.Clear;
- FullRefresh;
- end;
- end;
-
- function TfrmSyncPhonebook.FindContact(Number: WideString): WideString;
- var
- Node :PVirtualNode;
- contact: PContactData;
- begin
- Result := '';
- Node := ListContacts.GetFirst;
- while Node <> nil do begin
- contact := ListContacts.GetNodeData(Node);
- if IsContactPhone(contact,Number) then begin
- Result := GetContactFullName(contact);
- break;
- end;
- Node := ListContacts.GetNext(Node);
- end;
- end;
-
- procedure TfrmSyncPhonebook.FormStorage1SavePlacement(Sender: TObject);
- var
- s: string;
- i: integer;
- begin
- with ListContacts.Header do begin
- s := IntToStr(SortColumn)+','+IntToStr(Ord(SortDirection));
- for i := 0 to Columns.Count-1 do
- s := s+','+IntToStr(Columns[i].Width)+','+IntToStr(Columns[i].Position);
- end;
- FormStorage1.StoredValue['ListHeader'] := s;
- end;
-
- procedure TfrmSyncPhonebook.FormStorage1RestorePlacement(Sender: TObject);
- var
- s: widestring;
- i: integer;
- begin
- s := FormStorage1.StoredValue['ListHeader'];
- if s <> '' then
- try
- with ListContacts.Header do begin
- SortColumn := StrToInt(GetFirstToken(s));
- SortDirection := TSortDirection(StrToInt(GetFirstToken(s)));
- for i := 0 to Columns.Count-1 do begin
- Columns[i].Width := StrToInt(GetFirstToken(s));
- Columns[i].Position := StrToInt(GetFirstToken(s));
- end;
- end;
- if FirstLast1.Checked then FirstLast1Click(FirstLast1)
- else FirstLast1Click(LastFirst1);
- except
- end;
- end;
-
- procedure TfrmSyncPhonebook.ListContactsHeaderMouseUp(Sender: TVTHeader;
- Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
- begin
- FormStorage1SavePlacement(nil);
- end;
-
- end.
-
-